package com.ruoyi.web.controller.wechat.service.Impl;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.config.impl.WxMaRedisBetterConfigImpl;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.config.WechatOpenProperties;
import com.ruoyi.common.entity.DO.wechat.ShopAppletCommitDO;
import com.ruoyi.common.exception.BusinessException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.web.controller.wechat.domain.WxOpenMaVersionInfoResult;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.redis.RedisTemplateWxRedisOps;
import me.chanjar.weixin.open.api.WxOpenMaBasicService;
import me.chanjar.weixin.open.api.impl.*;
import me.chanjar.weixin.open.bean.ma.privacy.SetPrivacySetting;
import me.chanjar.weixin.open.bean.message.WxOpenMaSubmitAuditMessage;
import me.chanjar.weixin.open.bean.result.*;
import org.apache.http.entity.ContentType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class WechatOpenServiceImpl extends WxOpenServiceImpl {
    private Logger logger = LoggerFactory.getLogger(getClass());

    private final static String CODE_PRIVACY_INFO_URL = "https://api.weixin.qq.com/wxa/security/get_code_privacy_info?access_token={ACCESS_TOKEN}";
    private final static String VERSION_INFO_URL = "https://api.weixin.qq.com/wxa/getversioninfo?access_token={ACCESS_TOKEN}";

    private RedisTemplateWxRedisOps redisOps;

    private RestTemplate restTemplate = new RestTemplate();

    private WxOpenMessageRouter wxOpenMessageRouter;

    @Resource
    private WechatOpenProperties wechatOpenProperties;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    public WechatOpenServiceImpl() {
        redisOps = new RedisTemplateWxRedisOps(stringRedisTemplate);
    }

    @PostConstruct
    public void init() {
        WxOpenInRedisTemplateConfigStorage inRedisConfigStorage = new WxOpenInRedisTemplateConfigStorage(stringRedisTemplate, "api_component_token");
        inRedisConfigStorage.setComponentAppId(wechatOpenProperties.getComponentAppId());
        inRedisConfigStorage.setComponentAppSecret(wechatOpenProperties.getComponentSecret());
        inRedisConfigStorage.setComponentToken(wechatOpenProperties.getComponentToken());
        inRedisConfigStorage.setComponentAesKey(wechatOpenProperties.getComponentAesKey());
        setWxOpenConfigStorage(inRedisConfigStorage);
        wxOpenMessageRouter = new WxOpenMessageRouter(this);
        wxOpenMessageRouter.rule().handler((wxMpXmlMessage, map, wxMpService, wxSessionManager) -> {
            logger.info("\n接收到 {} 公众号请求消息，内容：{}", wxMpService.getWxMpConfigStorage().getAppId(), wxMpXmlMessage);
            return null;
        }).next();
    }

    /**
     * 获取小程序获取基本信息
     *
     * @param appId
     * @return
     */
    public WxFastMaAccountBasicInfoResult getAppletInfo(String appId) {
        WxMaService wxMaService = new WxOpenMaServiceImpl(this.getWxOpenComponentService(), appId, new WxMaRedisBetterConfigImpl(redisOps, wechatOpenProperties.getAppletKeyPrefix()));
        WxOpenMaBasicService wxOpenMaService = new WxOpenMaBasicServiceImpl(wxMaService);
        try {
            return wxOpenMaService.getAccountBasicInfo();
        } catch (WxErrorException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取小程序已设置的所有类目
     *
     * @param appId
     * @return
     */
    public WxFastMaBeenSetCategoryResult getCategory(String appId) {
        WxMaService wxMaService = new WxOpenMaServiceImpl(this.getWxOpenComponentService(), appId, new WxMaRedisBetterConfigImpl(redisOps, wechatOpenProperties.getAppletKeyPrefix()));
        WxOpenMaBasicService wxOpenMaService = new WxOpenMaBasicServiceImpl(wxMaService);
        try {
            return wxOpenMaService.getCategory();
        } catch (WxErrorException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 设置小程序用户隐私保护指引
     *
     * @param appId
     * @return
     */
    public void setPrivacySetting(String appId, SetPrivacySetting dto) {
        WxMaService wxMaService = new WxOpenMaServiceImpl(this.getWxOpenComponentService(), appId, new WxMaRedisBetterConfigImpl(redisOps, wechatOpenProperties.getAppletKeyPrefix()));
        WxOpenMaPrivacyServiceImpl wxOpenMaService = new WxOpenMaPrivacyServiceImpl(wxMaService);
        try {
            wxOpenMaService.setPrivacySetting(dto);
        } catch (WxErrorException e) {
            e.printStackTrace();
            throw new BusinessException(e.getMessage());
        }
    }

    /**
     * 查询指定审核单状态
     *
     * @param appId
     * @return
     */
    public WxOpenMaQueryAuditResult getAuditResult(String appId, Long auditid) {
        WxOpenMaServiceImpl wxMaService = new WxOpenMaServiceImpl(this.getWxOpenComponentService(), appId, new WxMaRedisBetterConfigImpl(redisOps, wechatOpenProperties.getAppletKeyPrefix()));
        try {
            return wxMaService.getAuditStatus(auditid);
        } catch (WxErrorException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 查询最新一次审核单状态
     *
     * @param appId
     * @return
     */
    public WxOpenMaQueryAuditResult getLastAuditResult(String appId) {
        WxOpenMaServiceImpl wxMaService = new WxOpenMaServiceImpl(this.getWxOpenComponentService(), appId, new WxMaRedisBetterConfigImpl(redisOps, wechatOpenProperties.getAppletKeyPrefix()));
        try {
            return wxMaService.getLatestAuditStatus();
        } catch (WxErrorException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 上传代码并生成体验版
     *
     * @param shopAppletCommitDO 小程序提交代码信息
     * @return
     */
    public WxOpenResult codeCommit(ShopAppletCommitDO shopAppletCommitDO, Object extJsonObj) {
        WxOpenMaServiceImpl wxMaService = new WxOpenMaServiceImpl(this.getWxOpenComponentService(), shopAppletCommitDO.getAppletAppId(), new WxMaRedisBetterConfigImpl(redisOps, wechatOpenProperties.getAppletKeyPrefix()));
        try {
            return wxMaService.codeCommit(shopAppletCommitDO.getTemplateId(), shopAppletCommitDO.getUserVersion(), shopAppletCommitDO.getUserDesc(), extJsonObj);
        } catch (WxErrorException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 提交代码审核
     *
     * @param wxOpenMaSubmitAuditMessage 小程序提交代码审核信息
     * @return
     */
    public WxOpenMaSubmitAuditResult submitAudit(String appId, WxOpenMaSubmitAuditMessage wxOpenMaSubmitAuditMessage) {
        WxOpenMaServiceImpl wxMaService = new WxOpenMaServiceImpl(this.getWxOpenComponentService(), appId, new WxMaRedisBetterConfigImpl(redisOps, wechatOpenProperties.getAppletKeyPrefix()));
        try {
            return wxMaService.submitAudit(wxOpenMaSubmitAuditMessage);
        } catch (WxErrorException e) {
            e.printStackTrace();
            throw new BusinessException(e.getMessage());
        }
    }

    /**
     * 加急代码审核
     *
     * @param appId   小程序appId
     * @param auditId 审核编号
     * @return
     */
    public void speedupAudit(String appId, Long auditId) {
        WxOpenMaServiceImpl wxMaService = new WxOpenMaServiceImpl(this.getWxOpenComponentService(), appId, new WxMaRedisBetterConfigImpl(redisOps, wechatOpenProperties.getAppletKeyPrefix()));
        try {
            boolean result = wxMaService.speedAudit(auditId);
            if (!result) {
                throw new BusinessException("加急失败！");
            }
        } catch (WxErrorException e) {
            e.printStackTrace();
            throw new BusinessException(e.getMessage());
        }
    }

    /**
     * 回退到上一版本
     *
     * @param appId 小程序appId
     * @return
     */
    public WxOpenResult backLatest(String appId) {
        WxOpenMaServiceImpl wxMaService = new WxOpenMaServiceImpl(this.getWxOpenComponentService(), appId, new WxMaRedisBetterConfigImpl(redisOps, wechatOpenProperties.getAppletKeyPrefix()));
        try {
            return wxMaService.revertCodeRelease();
        } catch (WxErrorException e) {
            e.printStackTrace();
            throw new BusinessException(e.getMessage());
        }
    }

    /**
     * 获取体验版二维码文件
     *
     * @param pagePath 指定二维码扫码后直接进入指定页面并可同时带上参数
     * @param params   页面参数
     * @return
     */
    public MultipartFile getDemoQrCode(String appId, String pagePath, Map<String, String> params) {
        WxOpenMaServiceImpl wxMaService = new WxOpenMaServiceImpl(this.getWxOpenComponentService(), appId, new WxMaRedisBetterConfigImpl(redisOps, wechatOpenProperties.getAppletKeyPrefix()));
        try {
            File resultFile = wxMaService.getTestQrcode(pagePath, params);
            FileInputStream fileInputStream = new FileInputStream(resultFile);
            return new MockMultipartFile(resultFile.getName(), resultFile.getName(),
                    ContentType.APPLICATION_OCTET_STREAM.toString(), fileInputStream);
        } catch (WxErrorException | IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 设置小程序服务域名
     *
     * @param appId
     * @return
     */
    public WxOpenMaDomainResult modifyDomain(String appId, String action, HashMap<String, List<String>> domains) {
        WxOpenMaDomainResult result = new WxOpenMaDomainResult();
        WxOpenMaServiceImpl wxMaService = new WxOpenMaServiceImpl(this.getWxOpenComponentService(), appId, new WxMaRedisBetterConfigImpl(redisOps, wechatOpenProperties.getAppletKeyPrefix()));
        try {
            if (!"get".equals(action)) {
                result = wxMaService.modifyDomain(action, domains.get("requestdomain"), domains.get("wsrequestdomain"), domains.get("uploaddomain"), domains.get("downloaddomain"));
            } else {
                result = wxMaService.getDomain();
            }

        } catch (WxErrorException e) {
            e.printStackTrace();
            result.setErrcode(String.valueOf(e.getError().getErrorCode()));
            result.setErrmsg(e.getError().getErrorMsg());
        }
        return result;
    }

    /**
     * 撤回小程序审核
     *
     * @param appId
     * @return
     */
    public void rollbackAudit(String appId) {
        WxOpenMaServiceImpl wxMaService = new WxOpenMaServiceImpl(this.getWxOpenComponentService(), appId, new WxMaRedisBetterConfigImpl(redisOps, wechatOpenProperties.getAppletKeyPrefix()));
        try {
            WxOpenResult result = wxMaService.undoCodeAudit();
            if (!result.isSuccess()) {
                throw new BusinessException(result.getErrcode());
            }
        } catch (WxErrorException e) {
            e.printStackTrace();
            throw new BusinessException(e.getError().getErrorMsg());
        }
    }

    /**
     * 发布已通过审核的小程序
     *
     * @param appId
     * @return
     */
    public void releaseAudited(String appId) {
        WxOpenMaServiceImpl wxMaService = new WxOpenMaServiceImpl(this.getWxOpenComponentService(), appId, new WxMaRedisBetterConfigImpl(redisOps, wechatOpenProperties.getAppletKeyPrefix()));
        try {
            WxOpenResult result = wxMaService.releaseAudited();
            if (!result.isSuccess()) {
                throw new BusinessException(result.getErrcode());
            }
        } catch (WxErrorException e) {
            if (85052 == e.getError().getErrorCode()) {
                //app is already released
                return;
            }
            throw new BusinessException(e.getError().getErrorMsg());
        }
    }

    /**
     * 查询小程序版本信息
     *
     * @return
     * @throws WxErrorException
     */
    public WxOpenResult getCodePrivacyInfo(String appId) {
        WxOpenResult wxOpenResult = new WxOpenResult();
        wxOpenResult.setErrcode("-1");
        wxOpenResult.setErrmsg("访问超时！");
        try {
            String accessToken = this.getWxOpenComponentService().getAuthorizerAccessToken(appId, true);
            JSONObject resultObj = restTemplate.getForObject(
                    CODE_PRIVACY_INFO_URL, JSONObject.class,
                    accessToken);
            if (null == resultObj) {
                return wxOpenResult;
            }
            if (resultObj.containsKey("errcode") && resultObj.containsKey("errmsg")) {
                wxOpenResult.setErrcode(resultObj.getString("errcode"));
                wxOpenResult.setErrmsg(resultObj.getString("errmsg"));
            }
        } catch (WxErrorException e) {
            e.printStackTrace();
            wxOpenResult.setErrcode(String.valueOf(e.getError().getErrorCode()));
            wxOpenResult.setErrmsg(wxOpenResult.getErrmsg());
        }
        return wxOpenResult;

    }

    /**
     * 查询小程序版本信息
     *
     * @return
     * @throws WxErrorException
     */
    public WxOpenMaVersionInfoResult getVersionInfo(String appId) {
        WxOpenMaVersionInfoResult wxOpenResult = new WxOpenMaVersionInfoResult();
        wxOpenResult.setErrcode("-1");
        wxOpenResult.setErrmsg("访问超时！");
        try {
            String accessToken = this.getWxOpenComponentService().getAuthorizerAccessToken(appId, true);
            JSONObject resultObj = restTemplate.postForObject(VERSION_INFO_URL, "{}", JSONObject.class, accessToken);
            if (null == resultObj) {
                return wxOpenResult;
            }
            if (!resultObj.containsKey("errcode") || !resultObj.containsKey("errmsg")) {
                return wxOpenResult;
            }
            wxOpenResult.setErrcode(resultObj.getString("errcode"));
            wxOpenResult.setErrmsg(resultObj.getString("errmsg"));
            if (!wxOpenResult.isSuccess()) {
                return wxOpenResult;
            }
            if (resultObj.containsKey("exp_info")) {
                JSONObject expInfo = resultObj.getJSONObject("exp_info");
                wxOpenResult.setExpDesc(expInfo.getString("exp_desc"));
                wxOpenResult.setExpVersion(expInfo.getString("exp_version"));
                wxOpenResult.setExpTime(DateUtils.convertToDate(expInfo.getLongValue("exp_time") * 1000));
            }
            if (resultObj.containsKey("release_info")) {
                JSONObject releaseInfo = resultObj.getJSONObject("release_info");
                wxOpenResult.setReleaseDesc(releaseInfo.getString("release_desc"));
                wxOpenResult.setReleaseVersion(releaseInfo.getString("release_version"));
                wxOpenResult.setReleaseTime(DateUtils.convertToDate(releaseInfo.getLongValue("release_time") * 1000));
            }
        } catch (WxErrorException e) {
            e.printStackTrace();
            wxOpenResult.setErrcode(String.valueOf(e.getError().getErrorCode()));
            wxOpenResult.setErrmsg(wxOpenResult.getErrmsg());
        }
        return wxOpenResult;
    }


    public WxOpenMessageRouter getWxOpenMessageRouter() {
        return wxOpenMessageRouter;
    }
}
